package javasec.contempt.views;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;

import java.io.FileInputStream;
import java.lang.Class;
import java.rmi.RemoteException;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;

import javasec.contempt.data.SeedConnection;
import javasec.contempt.data.SeedConnector;
import javasec.contempt.dialogs.KeyImportDialog;
import javasec.contempt.dialogs.KeyWindow;
import javasec.contempt.dialogs.ObjectDialog;
import javasec.contempt.dialogs.StringDialog;
import javasec.seed.ManagerSeedInterface;
import javasec.seed.SeedInterface;
import javasec.seed.SeedMethod;

import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.part.*;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.graphics.Image;
import org.eclipse.jface.action.*;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.ui.*;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.SWT;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.osgi.framework.Bundle;


public class ConnectionsView extends ViewPart
{
	private TreeViewer viewer;
	private Action doubleClickAction;
	public static TreeParent invisibleRoot; // the root of the tree
	
	// basic tree code to be used with MethodNode
	class TreeObject implements IAdaptable
	{
		private String name;
		private TreeParent parent;
		
		public TreeObject(String name)
		{
			this.name = name;
		}
		public String getName()
		{
			return name;
		}
		public void setName(String newName)
		{
			name=newName;
		}
		
		public void setParent(TreeParent parent)
		{
			this.parent = parent;
		}
		public TreeParent getParent()
		{
			return parent;
		}
		public String toString()
		{
			return getName();
		}
		public Object getAdapter(Class key)
		{
			return null;
		}
	}
	
	// basic tree code to be used with SeedNode
	class TreeParent extends TreeObject
	{
		private ArrayList<TreeObject> children;
		public TreeParent(String name)
		{
			super(name);
			children = new ArrayList<TreeObject>();
		}
		public void addChild(TreeObject child)
		{
			viewer.add(this,child);
			children.add(child);
			child.setParent(this);
		}
		public void removeChild(TreeObject child)
		{
			viewer.remove(child);
			children.remove(child);
			child.setParent(null);
		}
		public TreeObject [] getChildren()
		{
			return children.toArray(new TreeObject[children.size()]);
		}
		public boolean hasChildren()
		{
			return children.size()>0;
		}
	}
	
class MethodNode extends TreeObject
	{
		SeedMethod method=null;
		String methodName=null;
		String[] argumentNames=null;
		Object[] arguments=null;
		
		public MethodNode(SeedMethod incomingMethod)
		{	
			super(incomingMethod.getName());
			
			method=incomingMethod;
			methodName=method.getName();
			
			// TODO make sure annotations match params
			
			String niceName="";
			niceName+=methodName;
			niceName+="(";
			
			argumentNames=method.getParameterNames();
			
			if(argumentNames!=null && argumentNames.length>0)
			{
				niceName+=argumentNames[0];
				for(int x=1;x<argumentNames.length;++x)
				{
					niceName+=", ";
					niceName+=argumentNames[x];
				}
			}
			niceName+=")";
			
			this.setName(niceName);
		}
		
		public void execute()
		{	
			Object result=null;
			
			if(argumentNames.length>0)
			{
				ObjectDialog objectDialog=new ObjectDialog(null,"invoke method",argumentNames,method.getParameterTypes());
				objectDialog.open();
				if(objectDialog.aborted)return;
				arguments=objectDialog.getArguments();
			}
		
			try
			{
				SeedInterface seed;
				seed=((SeedNode)this.getParent()).seed;
				result=seed.invokeMethod(method.getName(),arguments);
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
			
			if(result==null){}
			else if((result instanceof String) && (!result.equals("")))
			{
				MessageDialog.openInformation(
					viewer.getControl().getShell(),
					"result",
					"'"+result+"'");
			}
			else
			{
				MessageDialog.openInformation(
					viewer.getControl().getShell(),
					"alert",
					"unknown return type '"+result.getClass().getSimpleName()+"'");				
			}
		}
	}

	class PropertyNode extends TreeObject
	{
		String name=null;
		Object value=null;
		SeedInterface seed=null;
		
		public PropertyNode(String n, Object v)
		{
			super(n);
			
			name=n;
			if(v==null)v="null";
			value=v.toString();;
			this.setName(name+": "+value);
		}
		
		public boolean setProperty(Object v)
		{
			value=v;
		
			// seed cannot be set in the contructor because the PropertyNode
			// does not yet have a parent when it is first instantiated
			if(seed==null) 
			{
				SeedNode seedNode=null;
				TreeParent tp=this.getParent();
				if(tp instanceof SeedNode)seedNode=(SeedNode)tp;
				seed=seedNode.seed;
			}
			
			try
			{
				seed.setProperty(name,value);
			}
			catch(Exception e)
			{
				e.printStackTrace();
				return false;
			}
			
			// change the name in the UI and refresh the viewer
			this.setName(name+": "+value);
			viewer.refresh();
			
			return true;
		}
	}
	
	
	public class SeedServerNode extends TreeParent
	{
		public boolean connected=false;
		public SeedConnection seedConnection=null;
		
		public SeedServerNode(SeedConnection connection)
		{
			super(connection.name+" ("+connection.location+")");
			seedConnection=connection;
			seedConnection.widget=this; // allow the connection to refrence back
			
			// connect to the local server by default
			if(seedConnection.location.equals("127.0.0.1"))seedConnection.connect();
			
			if(seedConnection.connected && seedConnection.rmiRegistry!=null)
			{
				connect();
			}
			else System.out.println("fail "+seedConnection.connected+" "+seedConnection.rmiRegistry);
		}
		
		public boolean addSeed(String seedName)
		{
			addChild(new SeedNode(seedName,seedConnection));
			
			viewer.refresh(this);
			return true;
		}
		
		public void populate()
		{
			System.out.println("populating stuff");
			
			// add the list of users
			TreeParent userParent=new TreeParent("users");
			this.addChild(userParent);
			try
			{
				for(String user:seedConnection.managerSeed.listUsers())
				{
					userParent.addChild(new TreeObject(user));
				}
				
				// add all the seed nodes
				for(String seedName:seedConnection.rmiRegistry.list())
				{
					if(seedName.equals("DataSeed")||seedName.equals("ManagerSeed"))continue;
					addChild(new SeedNode(seedName,seedConnection));
				}
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
			
			viewer.expandAll();	
		}
		
		public void connect()
		{
			System.out.println("attempting to connect the UI");
			if(connected==true)return;
			connected=true;
			
			// tell the seed connection to connect
			seedConnection.connect();
			
			if(seedConnection.connected)
			{
				populate();
			}
			else connected=false;
			
			viewer.refresh(this);
		}
		
		public void disconnect()
		{
			if(connected==false)return;
			connected=false;
			
			for(TreeObject seedNode:getChildren())
			{
				// remove all the children when you disconnect
				removeChild(seedNode);
			}
			
			viewer.refresh(this); // refresh the tree viewer
			
			// make sure the seedConnection has been disconnected
			if(seedConnection.connected==true)seedConnection.disconnect();
		}
	}
	
	class SeedNode extends TreeParent
	{
		public SeedInterface seed=null;
		public boolean active=false;
			
		// create a new SeedNode UI object
		// 
		public SeedNode(String name, SeedConnection seedConnection)
		{
			super(name);
			SeedMethod[] methods=null;
			if(seedConnection==null)return;
			active=true;
			
			// list the properties for this seed
			try
			{
				seed=(SeedInterface)seedConnection.rmiRegistry.lookup(name);
				HashMap<String,Object> properties=seed.getProperties();
				
				for(String key:properties.keySet())
				{
					PropertyNode propertyNode=new PropertyNode(key,properties.get(key));
					this.addChild(propertyNode);
				}
			}
			catch(Exception e)
			{
				e.printStackTrace();
				return;
			}
			
			// list the methods for this seed
			try
			{
				methods=seed.getMethods();
			}
			catch(Exception e)
			{
				e.printStackTrace();
				return;
			}
			
			for(int x=0;x<methods.length;++x)
			{
				MethodNode methodNode=new MethodNode(methods[x]);
				this.addChild(methodNode);
			}
		}
	}
		
	class ViewContentProvider implements IStructuredContentProvider, ITreeContentProvider
	{
		private TreeParent invisibleRoot;

		public void inputChanged(Viewer v, Object oldInput, Object newInput)
		{
		}
		public void dispose()
		{
		}
		
		public Object[] getElements(Object parent)
		{
			if (parent.equals(getViewSite()))
			{
				if (invisibleRoot==null) initialize();
				return getChildren(invisibleRoot);
			}
			return getChildren(parent);
		}
		
		public Object getParent(Object child)
		{
			if (child instanceof TreeObject)
			{
				return ((TreeObject)child).getParent();
			}
			return null;
		}
		
		public Object [] getChildren(Object parent)
		{
			if (parent instanceof TreeParent)
			{
				return ((TreeParent)parent).getChildren();
			}
			return new Object[0];
		}
		
		public boolean hasChildren(Object parent)
		{
			if (parent instanceof TreeParent)
				return ((TreeParent)parent).hasChildren();
			return false;
		}
		
		private void initialize() // recursively build the hierarchy
		{
			invisibleRoot = new TreeParent("");
			ConnectionsView.invisibleRoot=invisibleRoot;
			
			if(SeedConnector.getConnections()!=null)
			{
				System.out.println("found some connections in the db");
				
				try
				{
					for(SeedConnection seedConnection:SeedConnector.getConnections())
					{
						System.out.println("adding "+seedConnection.name);
						invisibleRoot.addChild(new SeedServerNode(seedConnection));	
					}
				}
				catch (Exception e)
				{
					e.printStackTrace();
				}	
			}
			else
			{
				invisibleRoot.addChild(new TreeObject("no connections"));
			}
		}
	}
	class ViewLabelProvider extends LabelProvider
	{

		public String getText(Object obj)
		{
			return obj.toString();
		}
		
		// TODO this is where we can put icon data
		public Image getImage(Object obj)
		{
			String imageKey = ISharedImages.IMG_OBJ_ELEMENT;
			if (obj instanceof TreeParent)
			   imageKey = ISharedImages.IMG_OBJ_FOLDER; // make tree parents look like a folder
			return PlatformUI.getWorkbench().getSharedImages().getImage(imageKey);
		}
	}
	
	/*  TODO come back to this later
	class NameSorter extends ViewerSorter
	{
	}
	*/

	public ConnectionsView()
	{
	}

	/**
	 * This is a callback that will allow us
	 * to create the viewer and initialize it.
	 */
	public void createPartControl(Composite parent)
	{
		try
		{
			viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
			//drillDownAdapter = new DrillDownAdapter(viewer);
			viewer.setContentProvider(new ViewContentProvider());
			viewer.setLabelProvider(new ViewLabelProvider());
			//viewer.setSorter(new NameSorter());
			viewer.setInput(getViewSite());
			viewer.expandAll();

			// Create the help context id for the viewer's control
			PlatformUI.getWorkbench().getHelpSystem().setHelp(viewer.getControl(), "javasec.contempt.viewer");
			makeActions();
			hookContextMenu();
			hookDoubleClickAction();
			contributeToActionBars();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	private void hookContextMenu() // menu when you right click
	{
		final MenuManager menuMgr = new MenuManager("#PopupMenu");
		menuMgr.setRemoveAllWhenShown(true);

		final Action connectAction=new Action("connect")
		{
			public void run()
			{
				ISelection selection=viewer.getSelection();
				Object object=((IStructuredSelection)selection).getFirstElement();
				
				if(object instanceof SeedServerNode)
				{
					SeedServerNode seedServerNode=(SeedServerNode)object;
					seedServerNode.connect();
				}
			}
		};
		
		final Action disconnectAction=new Action("disconnect")
		{
			public void run()
			{
				ISelection selection=viewer.getSelection();
				Object object=((IStructuredSelection)selection).getFirstElement();
				
				if(object instanceof SeedServerNode)
				{
					SeedServerNode seedServerNode=(SeedServerNode)object;	
					seedServerNode.disconnect();
				}
			}
		};
		
		final Action loadSeedAction=new Action("select seed")
		{
			public void run()
			{
				ISelection selection=viewer.getSelection();
				Object object=((IStructuredSelection)selection).getFirstElement();
				if(!(object instanceof SeedServerNode))return;
				SeedServerNode selectedSeedServer=(SeedServerNode)object;
				
				Shell shell=new Shell(Display.getDefault());
				FileDialog dialog=new FileDialog(shell,SWT.OPEN);
				File seedDirectory=null;
				
				seedDirectory=new File(System.getProperty("user.home")+File.separator+".contempt"+File.separator+"seeds");
				
				if(seedDirectory.exists())dialog.setFilterPath(seedDirectory.getPath());
				dialog.setFilterExtensions(new String[]{"*.jar","*"});
				
				String fileSelected=dialog.open();
				if(fileSelected==null)return; // make sure they selected something
				System.out.println("selected "+fileSelected);
				
				try
				{
					File seedFile=new File(fileSelected);
					String seedName=seedFile.getName().split("\\.")[0];
					byte[] data=new byte[(int) seedFile.length()];
					new FileInputStream(seedFile).read(data,0,data.length);
					selectedSeedServer.seedConnection.managerSeed.loadSeed(seedName,data);
					Thread.sleep(500); // sleep for a half second to wait for seed to settle
					
					// add the seed to the UI
					selectedSeedServer.addSeed(seedFile.getName().split("\\.")[0]);
				}
				catch (Exception e)
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				}		
			}	
		};
		
		
		final Action unloadModuleAction=new Action("unload seed")
		{
			public void run()
			{
				ISelection selection=viewer.getSelection();
				Object object=((IStructuredSelection)selection).getFirstElement();
				if(!(object instanceof SeedNode))return;
				
				SeedNode seedNode=(SeedNode)object;
				SeedServerNode seedServerNode=(SeedServerNode)seedNode.getParent();
				
				try // delete the jar on the server side
				{
					seedServerNode.seedConnection.managerSeed.unloadSeed(seedNode.getName());
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}
				
				seedServerNode.removeChild(seedNode);
				viewer.refresh(this);
			}
		};

		final Action shutdownAction=new Action("shutdown server")
		{
			public void run()
			{
				ISelection selection=viewer.getSelection();
				Object object=((IStructuredSelection)selection).getFirstElement();
				if(!(object instanceof SeedServerNode))return;
				
				SeedServerNode seedServerNode=(SeedServerNode)object;
				
				try // delete the jar on the server side
				{
					seedServerNode.seedConnection.managerSeed.shutdown();
				}
				catch(Exception e) 
				{
					// this will always fail because of abrupt disconnect before the return
				}
	
				viewer.refresh(object);
			}
		};

		
		final Action importUserAction=new Action("import user")
		{
			public void run()
			{
				ISelection selection=viewer.getSelection();
				Object object=((IStructuredSelection)selection).getFirstElement();
				TreeParent treeParent=null;
				SeedServerNode selectedSeedServer=null;
				
				// get a handle on the tree object, and the selected server
				
				if(object instanceof TreeParent)treeParent=(TreeParent)object;
				else return;
					
				if(treeParent.getParent()!=null && treeParent.getParent() instanceof SeedServerNode)
					selectedSeedServer=(SeedServerNode)treeParent.getParent();
				else return;
				
				try
				{
					KeyImportDialog importDialog=new KeyImportDialog(null,"import user");
					importDialog.open();
					if(importDialog.aborted)return;
					if(importDialog.certificate==null)return;
					if(importDialog.alias==null)return;

					// add the user to the remote server
					selectedSeedServer.seedConnection.managerSeed.addUser(importDialog.alias, importDialog.certificate);
					treeParent.addChild(new TreeObject(importDialog.alias));
					
					// add the user to list of friends
					KeyWindow.instance.friendsStore.setCertificateEntry(importDialog.alias, importDialog.certificate);
					KeyWindow.instance.friendsStore.store(new FileOutputStream(SeedConnector.friendsPath),SeedConnector.globalPass.toCharArray());
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}
				
				viewer.refresh(this);
			}
		};

		final Action deleteUserAction=new Action("delete user")
		{
			public void run()
			{
				ISelection selection=viewer.getSelection();
				Object object=((IStructuredSelection)selection).getFirstElement();
				TreeObject treeObject=null;
				TreeParent treeParent=null;
				SeedServerNode selectedSeedServer=null;
				
				// get a handle on the tree object, and the selected server
				if(object instanceof TreeObject)treeObject=(TreeObject)object;
				else return;
				
				if(treeObject.getParent()!=null && treeObject.getParent() instanceof TreeParent)
					treeParent=(TreeParent)treeObject.getParent();
				else return;
					
				if(treeParent.getParent()!=null && treeParent.getParent() instanceof SeedServerNode)
					selectedSeedServer=(SeedServerNode)treeParent.getParent();
				else return;
				
				// delete the user
				try
				{
					selectedSeedServer.seedConnection.managerSeed.deleteUser(treeObject.getName());
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}
				
				treeParent.removeChild(treeObject);
				viewer.refresh(this);
			}
		};
	
		
		final Action newConnectionAction=new Action("new connection")
		{
			public void run()
			{
				// prompt for the location of the server
				
				StringDialog dialog=new StringDialog(null,"new connection",new String[]{"name ","location "});
				dialog.open();
				if(dialog.aborted)return;
				String name=dialog.getValues()[0];
				String location=dialog.getValues()[1];
			
				SeedConnection newConnection=null;
				newConnection=SeedConnector.newConnection(name,location);
				invisibleRoot=new SeedServerNode(newConnection);
				viewer.refresh();
			}
		};
		
		final Action removeConnectionAction=new Action("remove connection")
		{
			public void run()
			{
				ISelection selection=viewer.getSelection();
				Object object=((IStructuredSelection)selection).getFirstElement();

				if(object instanceof SeedServerNode)
				{
					SeedServerNode server=(SeedServerNode)object;
					
					if(server.connected)server.disconnect();
					SeedConnector.removeConnection(server.seedConnection);
					server.getParent().removeChild(server);
					viewer.refresh();
				}
			}
		};

		final Action renameConnectionAction=new Action("rename connection")
		{
			public void run()
			{
				ISelection selection=viewer.getSelection();
				Object object=((IStructuredSelection)selection).getFirstElement();

				if(object instanceof SeedServerNode)
				{
					SeedServerNode server=(SeedServerNode)object;
			
					StringDialog dialog=new StringDialog(null,"rename connection",new String[]{"new name: "});
					dialog.open();
					if(dialog.aborted)return;
					String newName=dialog.getValues()[0];
					
					SeedConnector.renameConnection(server.seedConnection,newName);
					server.setName(newName+" ("+server.seedConnection.location+")");
					viewer.refresh();
				}
			}
		};
		
		final Action connectAllAction=new Action("connect all")
		{
			public void run()
			{
				// run through and connect all
				for(SeedConnection conn:SeedConnector.getConnections())
				{
					conn.connect();
				}
			}
		};
		
		final Action disconnectAllAction=new Action("disconnect all")
		{
			public void run()
			{
				// run through and disconnect all
				for(SeedConnection conn:SeedConnector.getConnections())
				{
					conn.disconnect();
				}
			}
		};
		
		menuMgr.addMenuListener(new IMenuListener()
		{
			public void menuAboutToShow(IMenuManager manager)
			{
				ISelection selection=viewer.getSelection();
				Object object=((IStructuredSelection)selection).getFirstElement();

				if(object instanceof TreeParent)
				{
					TreeParent treeParent=(TreeParent)object;
					if(treeParent.getName().equals("users"))
					{
						MenuManager addUserMenu=new MenuManager("add user");
						
						try
						{
							if(KeyWindow.instance==null)KeyWindow.instance=new KeyWindow();
							Enumeration<String> friends=KeyWindow.instance.friendsStore.aliases();
							while(friends.hasMoreElements())
							{
								final String friend=friends.nextElement();
								addUserMenu.add(new Action(friend)
								{
									public void run()
									{
										// see which server is selected
										ISelection selection=viewer.getSelection();
										Object object=((IStructuredSelection)selection).getFirstElement();
										TreeParent treeParent=null;
										SeedServerNode selectedSeedServer=null;
										
										if(object instanceof TreeParent)treeParent=(TreeParent)object;
										else return;
											
										// get a handle on the selected seed server
										if(treeParent.getParent()!=null && treeParent.getParent() instanceof SeedServerNode)
											selectedSeedServer=(SeedServerNode)treeParent.getParent();
										else return;
										
										// look for key in keystore, and add it to remote server
										try
										{
											Certificate cert=KeyWindow.instance.friendsStore.getCertificate(friend);
											if(!(cert instanceof X509Certificate))return; // instanceof does the null check
											String ret=selectedSeedServer.seedConnection.managerSeed.addUser(friend,(X509Certificate)cert);
											if(ret.equals("success"))treeParent.addChild(new TreeObject(friend));
										}
										catch(Exception e)
										{
											e.printStackTrace();
										}
									}
								});
							}
						}
						catch(Exception e)
						{
							e.printStackTrace();
						}
						
						addUserMenu.add(new Separator());
						addUserMenu.add(importUserAction);
						
						menuMgr.add(addUserMenu);
						menuMgr.add(new Separator());
					}
				}
				if(object instanceof TreeObject)
				{
					TreeObject treeObject=(TreeObject)object;
					if(treeObject.getParent()!=null && (treeObject.getParent()).getName().equals("users"))
					{
						menuMgr.add(deleteUserAction);
						menuMgr.add(new Separator());
					}
				}
				if(object instanceof SeedServerNode)
				{
					menuMgr.add(connectAction);
					menuMgr.add(disconnectAction);
					
					final SeedServerNode seedServerNode=(SeedServerNode)object;
					MenuManager loadSeedMenu=new MenuManager("load seed");
					File seedDir=new File(SeedConnector.contemptPath+File.separator+"seeds");
					final Bundle seedBundle=Platform.getBundle("javasec.seed");
					
					Enumeration<String> paths=seedBundle.getEntryPaths("/seeds");
					while(paths.hasMoreElements())
					{
						final String path=paths.nextElement();
						final String seedName=path.split("/")[1].split("\\.")[0];
						if(seedName.equals("SeedServer"))continue;
						loadSeedMenu.add(new Action(seedName)
						{
							public void run() // read seed out of seed-core plugin, and load over the network
							{
								int len;
								byte[] buf=new byte[1024];
								InputStream inStream=null;
								ByteArrayOutputStream outStream=new ByteArrayOutputStream();
								
								try
								{
									// get a handle on the seed file
									inStream=FileLocator.openStream(seedBundle,new Path(path),false);
									
									// read the file into a byte buffer
									while(-1!=(len=inStream.read(buf)))outStream.write(buf,0,len);
									
									// write the byte buffer to the network
									seedServerNode.seedConnection.managerSeed.loadSeed(seedName,outStream.toByteArray());
								}
								catch(Exception e)
								{
									e.printStackTrace();
								}
							}
						});	
					}
					
					loadSeedMenu.add(new Separator());
					loadSeedMenu.add(loadSeedAction); // external load action
					
					menuMgr.add(loadSeedMenu);
					
					menuMgr.add(new Separator());
					menuMgr.add(renameConnectionAction);
					menuMgr.add(removeConnectionAction);
					menuMgr.add(shutdownAction);
				}
				else if(object instanceof SeedNode)
				{
					//menuMgr.add(loadModuleAction);
					menuMgr.add(unloadModuleAction);
				}
				else if(object instanceof MethodNode)
				{
					//menuMgr.add(loadModuleAction);
					//menuMgr.add(unloadModuleAction);
				}
				else // if you click outside of the tree structure
				{
				}
				
				// always add these to the end
				menuMgr.add(new Separator());
				menuMgr.add(newConnectionAction);
				menuMgr.add(connectAllAction);
				menuMgr.add(disconnectAllAction);
			}
		});
		
		
		Menu menu = menuMgr.createContextMenu(viewer.getControl());
		viewer.getControl().setMenu(menu);
		getSite().registerContextMenu(menuMgr, viewer);

	}

	private void contributeToActionBars()
	{
	}

	private void makeActions()
	{
		doubleClickAction = new Action()
		{
			public void run()
			{
				ISelection selection = viewer.getSelection();
				Object selected = ((IStructuredSelection)selection).getFirstElement();
				
				if(selected instanceof TreeParent)
				{
					boolean expanded;
					expanded=viewer.getTree().getSelection()[0].getExpanded();
					viewer.getTree().getSelection()[0].setExpanded(!expanded);
					viewer.refresh(this);
				}
				else if(selected instanceof MethodNode)
				{
					try
					{
						((MethodNode) selected).execute();
					}
					catch(Exception e)
					{
						e.printStackTrace();
					}
				}
				else if(selected instanceof PropertyNode)
				{
					try
					{
						PropertyNode propertyNode=(PropertyNode)selected;
						ObjectDialog propertyDialog=new ObjectDialog(null,"set property",new String[]{propertyNode.name},new Class[]{propertyNode.value.getClass()});
						propertyDialog.open();
						if(propertyDialog.aborted)return;
						Object value=propertyDialog.getArguments()[0];
						propertyNode.setProperty(value);
					}
					catch(Exception e)
					{
						e.printStackTrace();
					}
				}
				else
				{
					//showMessage("I don't know what you were clicking on..");
				}
			}
		};
	}
	
	private void hookDoubleClickAction()
	{
		viewer.addDoubleClickListener(new IDoubleClickListener()
		{
			public void doubleClick(DoubleClickEvent event)
			{
				doubleClickAction.run();
			}
		});
	}
	
	private void showMessage(String message)
	{
		MessageDialog.openInformation(
			viewer.getControl().getShell(),
			"Live Seed View",
			message);
	}
	
	/**
	 * Passing the focus request to the viewer's control.
	 */
	public void setFocus()
	{
		viewer.getControl().setFocus();
	}
}